using MultiAgentsClient.ChatDataStructures;
using MultiAgentsClient.Manager.DataModel;
using MultiAgentsClient.Service.SignalRService;
using MultiAgentsShared;
using TextCopy;
using static MultiAgentsShared.ToolSetCollection;
using ApiRequest = MultiAgentsClient.Service.SignalRService.SignalRAgentService.ApiRequestType;

namespace MultiAgentsClient.Manager;

public class AgentManager : ManagerBase
{
    private readonly SignalRAgentService signalRAgentService;
    private readonly UserDataModel userDataModel;
    private readonly SystemConfigDataModel systemConfigDataModel;

    #region events
    // recieve command from UI
    public record CreateNewAgentCommand();
    public record GenerateMessageCommand(List<PresetMessageDisp> MessagesList, float Temperature, string Model);
    public record RemoveAgentCommand(int AgentId);
    public record LoadAgentCommand(int AgentId);

    public record LoadAgentByShareCodeCommand(string AgentJson);
    public record ShareAgentCommand(int AgentId);
    public record UpdateAgentCommand(AgentTemplate AgentTemplate);

    // recieve command from signalR
    public record CreateNewAgentResponseCommand(AgentTemplate Agent);
    public record GenerateMessageResponseCommand(string ResponseMessage);
    public record RemoveAgentResponseCommand(int AgentId);
    public record UpdateAgentResponseCommand(AgentTemplate Agent);
    
    // send command to UI
    public record CreateNewAgentCompleteCommand(AgentDisp AgentDisp);
    public record GenerateMessageCompleteCommand(string ResponseMessage);
    public record RemoveAgentCompleteCommand(int Agent);
    public record UpdateAgentCompleteCommand(AgentDisp AgentConfigDisp);
    public record LoadAgentCompleteCommand(AgentTemplate Agent);
    #endregion

    public AgentManager(
        SystemConfigDataModel systemConfigDataModel,
        SignalRAgentService signalRAgentService,
        UserDataModel userDataModel)
    {
        this.signalRAgentService = signalRAgentService;
        this.userDataModel = userDataModel;
        this.systemConfigDataModel = systemConfigDataModel;

        eventBus.Subscribe<CreateNewAgentCommand>(cmd => { Task.Run(() => CreateNewAgentCommandHandler(cmd)); });
        eventBus.Subscribe<GenerateMessageCommand>(cmd => { Task.Run(() => GenerateMessageCommandHandler(cmd)); });
        eventBus.Subscribe<RemoveAgentCommand>(cmd => { Task.Run(() => RemoveAgentCommandHandler(cmd)); });
        eventBus.Subscribe<LoadAgentByShareCodeCommand>(cmd => { Task.Run(() => LoadAgentByShareCodeCommandHandler(cmd)); });
        eventBus.Subscribe<ShareAgentCommand>(cmd => { Task.Run(() => ShareAgentCommandHandler(cmd)); });
        eventBus.Subscribe<UpdateAgentCommand>(cmd => { Task.Run(() => UpdateAgentCommandHandler(cmd)); });
        eventBus.Subscribe<LoadAgentCommand>(cmd => { Task.Run(() => LoadAgentCommandHandler(cmd)); });

        eventBus.Subscribe<CreateNewAgentResponseCommand>(cmd => { Task.Run(() => CreateNewAgentResponseCommandHandler(cmd)); });
        eventBus.Subscribe<GenerateMessageResponseCommand>(cmd => { Task.Run(() => GenerateMessageResponseCommandHandler(cmd)); });
        eventBus.Subscribe<RemoveAgentResponseCommand>(cmd => { Task.Run(() => RemoveAgentResponseCommandHandler(cmd)); });
        eventBus.Subscribe<UpdateAgentResponseCommand>(cmd => { Task.Run(() => UpdateAgentResponseCommandHandler(cmd)); });
    }

    #region request
    private async ValueTask CreateNewAgentCommandHandler(CreateNewAgentCommand _)
    {
        await signalRAgentService.SendSignalRRequest(ApiRequest.CreateNewAgentRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
            });
    }

    private async ValueTask GenerateMessageCommandHandler(GenerateMessageCommand cmd)
    {
        List<string> messages = [];
        foreach (PresetMessageDisp msg in cmd.MessagesList)
        {
            messages.Add(new ChatMessageData()
            {
                role = msg.Role,
                content = msg.Message,
            }.ConvertToJson());
        }
        await signalRAgentService.SendSignalRRequest(ApiRequest.GenerateMessageRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "messages", messages },
                { "temperature", cmd.Temperature },
                { "model", cmd.Model },
            });
    }

    private async ValueTask LoadAgentByShareCodeCommandHandler(LoadAgentByShareCodeCommand cmd)
    {
        await signalRAgentService.SendSignalRRequest(ApiRequest.LoadAgentByShareCodeRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "agentJson", cmd.AgentJson },
            });
    }

    private async ValueTask RemoveAgentCommandHandler(RemoveAgentCommand cmd)
    {
        await signalRAgentService.SendSignalRRequest(ApiRequest.RemoveAgentRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "agentId", cmd.AgentId },
            });
    }

    private void ShareAgentCommandHandler(ShareAgentCommand cmd)
    {
        AgentTemplate? agentToShare = userDataModel.customAgents.FirstOrDefault(a => a.Id == cmd.AgentId);
        if (agentToShare == null)
        {
            return;
        }

        ClipboardService.SetText(agentToShare.ConvertToJson());
    }

    public async void UpdateAgentCommandHandler(UpdateAgentCommand cmd)
    {
        cmd.AgentTemplate.UserId = userDataModel.Id;

        List<string> tools = [];
        foreach (ToolSet toolSet in ToolSets)
        {
            if (cmd.AgentTemplate.AllowedTools.Contains(toolSet.ToolSetName))
            {
                foreach (var tool in toolSet.ToolDefinitions.Keys)
                {
                    tools.Add(tool.Function.Name);
                }
            }
        }
        cmd.AgentTemplate.AllowedTools = tools;

        await signalRAgentService.SendSignalRRequest(ApiRequest.UpdateAgentRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "agentTemplate", SerializableObjectBase.ConvertToJson(cmd.AgentTemplate) },
            });
    }

    public void LoadAgentCommandHandler(LoadAgentCommand cmd)
    {
        AgentTemplate? agentToLoad = userDataModel.customAgents.FirstOrDefault(a => a.Id == cmd.AgentId);
        if (agentToLoad != null)
        {
            eventBus.Publish(new LoadAgentCompleteCommand(agentToLoad));
        }
    }
    #endregion

    #region response
    private void CreateNewAgentResponseCommandHandler(CreateNewAgentResponseCommand cmd)
    {
        userDataModel.customAgents.Add(cmd.Agent);

        eventBus.Publish(new CreateNewAgentCompleteCommand(cmd.Agent.ToDisp()));
        eventBus.Publish(new LoadAgentCompleteCommand(cmd.Agent));
    }

    private void GenerateMessageResponseCommandHandler(GenerateMessageResponseCommand cmd)
    {
        eventBus.Publish(new GenerateMessageCompleteCommand(cmd.ResponseMessage));
    }

    private void RemoveAgentResponseCommandHandler(RemoveAgentResponseCommand cmd)
    {
        AgentTemplate? agentToRemove = userDataModel.customAgents.FirstOrDefault(a => a.Id == cmd.AgentId);
        if (agentToRemove != null)
        {
            userDataModel.customAgents.Remove(agentToRemove);
        }

        eventBus.Publish(new RemoveAgentCompleteCommand(cmd.AgentId));
    }

    private void UpdateAgentResponseCommandHandler(UpdateAgentResponseCommand cmd)
    {
        AgentTemplate agentTemplate = cmd.Agent;

        var agentIndex = userDataModel.customAgents.FindIndex(a => a.Id == agentTemplate.Id);

        if (agentIndex != -1)
        {
            userDataModel.customAgents[agentIndex] = agentTemplate;
        }
        eventBus.Publish(new UpdateAgentCompleteCommand(new AgentDisp(agentTemplate.Id, agentTemplate.Name, true)));
    }
    #endregion
}
